/**
 @file sys_usw_fpa.c

   @date 2016-08-01

   @version v3.0

 */

/****************************************************************************
*
* Header Files
*

****************************************************************************/
#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
/*#include <time.h>*/

#include "sys_usw_fpa.h"

#define SUB_BLOCK_END   (pb->start_offset[key_size] + (pb->sub_entry_count[key_size] - 1))
#define SUB_BLOCK_START       (pb->start_offset[key_size])

extern bool
_fpa_usw_get_shift_count(int32 null, int32 target, int32 dir, int32* count);
extern int32
_fpa_usw_get_shift_direction(int32 prev_null_index,
                         int32 target_index,
                         int32 next_null_index,
                         int32* dir);

int32
fpa_get_index_by_pe_idx(uint16 block_entry_count, uint16 sub_entry_count_160, int32 pe_idx)
{
    int32 fpa_idx = 0;
    int32 local_idx = 0;

    if (pe_idx >= block_entry_count*2)
    {
        local_idx = pe_idx - block_entry_count*2;
        fpa_idx = local_idx + sub_entry_count_160*2;
    }
    else if(pe_idx>= block_entry_count)
    {
        local_idx = pe_idx - block_entry_count;
        fpa_idx = local_idx + sub_entry_count_160;
    }
    else
    {
        local_idx = pe_idx;
        fpa_idx = local_idx;
    }

    return fpa_idx;
}


int32
fpa_get_index_by_fpa_idx(ctc_fpa_block_t* pb, int32 fpa_idx)
{
    int32 pe_index = 0;
    int32 local_idx = 0;

    if (fpa_idx >= pb->sub_entry_count[1]*2)
    {
        local_idx = fpa_idx - pb->sub_entry_count[1]*2;
        pe_index = local_idx + pb->entry_count*2;
    }
    else if(fpa_idx >= pb->sub_entry_count[1])
    {
        local_idx = fpa_idx - pb->sub_entry_count[1];
        pe_index = local_idx + pb->entry_count;
    }
    else
    {
        pe_index = fpa_idx;
    }

    return pe_index;
}

ctc_fpa_block_t*
fpa_get_local_info_by_fpa_idx(ctc_fpa_block_t* pb, int32 fpa_idx, int32* p_local_idx)
{
    int32 local_idx = 0;
    ctc_fpa_block_t* pb_part = NULL;

    if (fpa_idx >= pb->sub_entry_count[1]*2)
    {
        local_idx = fpa_idx - pb->sub_entry_count[1]*2;
        pb_part = pb->next->next;
    }
    else if(fpa_idx >= pb->sub_entry_count[1])
    {
        local_idx = fpa_idx - pb->sub_entry_count[1];
        pb_part = pb->next;
    }
    else
    {
        local_idx = fpa_idx;
        pb_part = pb;
    }

    *p_local_idx = local_idx;

    return pb_part;

}


int32
fpa_get_index_by_fpa_idx_adjust(ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info, int32 fpa_idx)
{
    int32 pe_index = 0;
    int32 local_idx = 0;
    uint32 adjust_cnt = 0;

    if (pb->sub_entry_count[0])
    {
        adjust_cnt = pb->sub_entry_count[1] - pb->sub_entry_count[0];
    }
    else if (p_info && (p_info->key160_count || p_info->key160_count_valid))
    {
        adjust_cnt = p_info->key160_count;
    }
    else
    {
        adjust_cnt = pb->sub_entry_count[1];
    }

    if (fpa_idx >= adjust_cnt*2)
    {
        local_idx = fpa_idx - adjust_cnt*2;
        pe_index = local_idx + pb->entry_count*2;
    }
    else if(fpa_idx >= adjust_cnt)
    {
        local_idx = fpa_idx - adjust_cnt;
        pe_index = local_idx + pb->entry_count;
    }
    else
    {
        pe_index = fpa_idx;
    }

    return pe_index;
}


ctc_fpa_block_t*
fpa_get_local_info_by_fpa_idx_adjust(ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info, int32 fpa_idx, int32* p_local_idx)
{
    int32 local_idx = 0;
    ctc_fpa_block_t* pb_part = NULL;
    uint32 adjust_cnt = 0;

    if (pb->sub_entry_count[0])
    {
        adjust_cnt = pb->sub_entry_count[1] - pb->sub_entry_count[0];
    }
    else if (p_info && (p_info->key160_count || p_info->key160_count_valid))
    {
        adjust_cnt = p_info->key160_count;
    }
    else
    {
        adjust_cnt = pb->sub_entry_count[1];
    }
    SYS_FPA_DBG_INFO("  [FPA] fpa_idx:%d, adjust_cnt: %d, part_num:%d \n", fpa_idx, adjust_cnt, pb->part_num);
    if (fpa_idx >= adjust_cnt*2 && pb->part_num > 2)
    {
        local_idx = fpa_idx - adjust_cnt*2;
        pb_part = pb->next->next;
    }
    else if(fpa_idx >= adjust_cnt  && pb->part_num > 1)
    {
        local_idx = fpa_idx - adjust_cnt;
        pb_part = pb->next;
    }
    else
    {
        local_idx = fpa_idx;
        pb_part = pb;
    }

    *p_local_idx = local_idx;

    return pb_part;

}

/*
 * move entry to new position in specific chip.
 */
STATIC int32
_fpa_usw_entry_move2(ctc_fpa_t* fpa, ctc_fpa_entry_t* pe, int32 amount, ctc_fpa_block_info_t* p_info)
{
    int32          tcam_idx_old = 0; /* Original entry tcam index.    */
    int32          tcam_idx_new = 0; /* Next tcam index for the entry.*/
    ctc_fpa_block_t* pb = NULL;             /* Field slice control.          */

    if (!pe)
    {
        return  CTC_E_NONE;/* skip */
    }
    fpa->get_info_by_pe(fpa->lchip, pe, &pb);
    CTC_PTR_VALID_CHECK(pb);

    if (pb->vblock && pe->key_size == CTC_FPA_KEY_SIZE_160)
    {
        int32 local_idx_old = 0;
        int32 local_idx_new = 0;
        int32 new_pe_idx = 0;
        ctc_fpa_block_t* pb_part_old = NULL;
        ctc_fpa_block_t* pb_part_new = NULL;

        tcam_idx_old = fpa_get_index_by_pe_idx(pb->entry_count, pb->sub_entry_count[CTC_FPA_KEY_SIZE_160], pe->offset_a);
        tcam_idx_new = tcam_idx_old + amount;
        pb_part_old = fpa_get_local_info_by_fpa_idx(pb, tcam_idx_old, &local_idx_old);
        pb_part_new = fpa_get_local_info_by_fpa_idx_adjust(pb, p_info, tcam_idx_new, &local_idx_new);
        if (pb_part_old == pb_part_new && local_idx_old == local_idx_new)
        {
            if (tcam_idx_new != tcam_idx_old)
            {
                if (pb->sub_entry_count[0] == 0)
                {
                    pb->vblock->entries[tcam_idx_old] = NULL;
                    pb->vblock->entries[tcam_idx_new] = pe;
                }
            }

            pb_part_new->entries[local_idx_new] = pe;

            SYS_FPA_DBG_INFO("Move entry:%d  index: [%d->%d], part[%d ->%d] [%d->%d] \n",
                       pe->entry_id,
                       tcam_idx_old,
                       tcam_idx_new,
                       pb_part_old->part,
                       pb_part_new->part,
                       local_idx_old,
                       local_idx_new);

            return CTC_E_NONE;
        }

        new_pe_idx = fpa_get_index_by_fpa_idx_adjust(pb, p_info, tcam_idx_new);

        /* Move the hardware entry, even if entry is not installed, because of scl need update key index in pe entry .*/
        CTC_ERROR_RETURN(fpa->entry_move_hw(fpa->lchip, pe, new_pe_idx));

        /* Move the software entry.*/
        pe->offset_a       = new_pe_idx;

        if (pb->sub_entry_count[0] == 0)
        {
            pb->vblock->entries[tcam_idx_old] = NULL;
            pb->vblock->entries[tcam_idx_new] = pe;
        }

        pb_part_old->entries[local_idx_old] = NULL;
        pb_part_new->entries[local_idx_new] = pe;

        if (pb_part_old != pb_part_new)
        {
            pb_part_old->free_count++;
            pb_part_old->sub_free_count[1]++;
            pb_part_new->free_count--;
            pb_part_new->sub_free_count[1]--;//

        }

        SYS_FPA_DBG_INFO("Move entry:%d  index: [%d->%d], part[%d ->%d] [%d->%d] \n",
                   pe->entry_id,
                   tcam_idx_old,
                   tcam_idx_new,
                   pb_part_old->part,
                   pb_part_new->part,
                   local_idx_old,
                   local_idx_new);

    }
    else
    {
        uint8 part = 0;
        ctc_fpa_block_t* pb_part = pb;

        if (amount == 0) /* move no where */
        {
            return CTC_E_NONE;
        }


        tcam_idx_old = pe->offset_a;
        tcam_idx_new = tcam_idx_old + amount;

        /* Move the hardware entry, even if entry is not installed, because of scl need update key index in pe entry .*/
        CTC_ERROR_RETURN(fpa->entry_move_hw(fpa->lchip, pe, tcam_idx_new));

        /* Move the software entry.*/
        pe->offset_a       = tcam_idx_new;

        pb->entries[tcam_idx_old] = NULL;
        pb->entries[tcam_idx_new] = pe;

        /*process link block*/
        for (part = 1; part < pe->key_size && pb_part->next; part++)
        {
            pb_part = pb_part->next;
            pb_part->entries[tcam_idx_old] = NULL;
            pb_part->entries[tcam_idx_new] = pe;
        }
    }

    return(CTC_E_NONE);
}

/*
 * shift up entries from target entry to prev null entry
 */
STATIC int32
_fpa_usw_entry_shift_up2(ctc_fpa_t* fpa,
                    ctc_fpa_block_t* pb,
                    int32 target_index,
                    int32 prev_null_index,
                    uint8 step,
                    uint32* move_num)
{
    int32 temp;

    /* Input parameter check. */
    CTC_PTR_VALID_CHECK(pb);

    temp = prev_null_index;

    /* start from prev-1:
     *  prev + 1 -- > prev
     *  prev + 2 -- > prev + 1
     *  ...
     *  target -- > target - 1
     */
    while ((temp < target_index))
    {
        /* Move the entry at the next index to the prev. empty index. */

        /* Perform entry move. */
        CTC_ERROR_RETURN(_fpa_usw_entry_move2(fpa, pb->entries[temp + step], -step, NULL));

        temp = temp + step;
    }

    temp = (target_index - prev_null_index)/step;
    *move_num = (temp < 0) ? 0 : temp;
    return(CTC_E_NONE);
}

/*
 * shift down entries from target entry to next null entry
 */
STATIC int32
_fpa_usw_entry_shift_down2(ctc_fpa_t* fpa,
                      ctc_fpa_block_t* pb,
                      int32 target_index,
                      int32 next_null_index,
                      uint8 step,
                      uint32* move_num)
{
    int32 temp;

    /* Input parameter check. */
    CTC_PTR_VALID_CHECK(pb);

    temp = next_null_index;

    /*
     * Move entries one step down
     *     starting from the last entry
     * start from prev-1:
     *  next - 1 -- > next
     *  next - 2 -- > next -1
     *  ...
     *  target -- > target + 1
     */
    while (temp > target_index)
    {
        /* Perform entry move. */
        CTC_ERROR_RETURN(_fpa_usw_entry_move2(fpa, pb->entries[temp - step], step, NULL));
        temp = temp - step;
    }

    *move_num = (next_null_index - target_index)/step;

    return(CTC_E_NONE);
}

STATIC int32
_fpa_usw_reorder_virtual(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, uint8 type, ctc_fpa_block_info_t* p_info)
{
    int32         idx;
    int32         revise;
    int32         t_idx;
    int32         o_idx;
    _fpa_target_t * target_a = NULL;
    int32         ret        = 0;
    uint8         step   = 1;
    uint32 start_offset = 0;
    uint32 old_start_offset = 0;
    uint32 full_num;
    uint32 old_full_num;
    uint32 free_num;
    uint32 real_num;             /* actual entry number */
    uint32 left_num;
    ctc_fpa_block_t* pb_real = NULL;
    int32 pos_a[5] = {-1,-1,-1,-1,-1};
    int8 dir0[5] = {0};
#ifndef CTC_SHELL_DEBUG_ON
    int8 dir1[5] = {0};
#endif
    uint8 i = 0;
    uint8 j = 0;
    int32 pos = -1;
    int32 local_idx_new = 0;
    ctc_fpa_block_t* pb_part_new = NULL;
    uint8 key_size = p_info->key_size;
    int16 start_move_num = p_info->start_move_num;
    int16 sub_count_vary = p_info->sub_count_vary;

    ctc_fpa_entry_t** p_tmp_entries = NULL;      /* pointer to entry*/

    SYS_FPA_DBG_FUNC();

    CTC_PTR_VALID_CHECK(pb);

    pb_real = pb;
    pb = pb->vblock;

    /* malloc a new array based on new exist entry*/
    old_start_offset = pb->start_offset[key_size];
    start_offset = pb->start_offset[key_size] + start_move_num;

    old_full_num = pb->sub_entry_count[key_size];
    full_num = pb->sub_entry_count[key_size] + sub_count_vary;
    free_num = pb->sub_free_count[key_size] + sub_count_vary;
    real_num = full_num - free_num; /* used entry count */

    if(0 == old_full_num || real_num == 0)
    {
        return CTC_E_NONE;
    }

    MALLOC_ZERO(MEM_FPA_MODULE, target_a, real_num * sizeof(_fpa_target_t))
    if(!target_a)
    {
       return CTC_E_NO_MEMORY;
    }

    MALLOC_ZERO(MEM_FPA_MODULE, p_tmp_entries, old_full_num * sizeof(ctc_fpa_entry_t*))
    if(!p_tmp_entries)
    {
       return CTC_E_NO_MEMORY;
    }

    sal_memcpy(p_tmp_entries, pb->entries, old_full_num * sizeof(ctc_fpa_entry_t*));


    /* save target idx to array */
    if (REORDE_TYPE_SCATTER == type)
    {
        for (t_idx = 0; t_idx < real_num; t_idx++)
        {
            target_a[t_idx].t_idx  = (full_num * t_idx / real_num)  + start_offset;
        }
    }
    else if (REORDE_TYPE_DECREASE == type) /* move up,make room for low prio entry*/
    {
        for (t_idx = 0; t_idx < real_num; t_idx++)
        {
            target_a[t_idx].t_idx  = t_idx + start_offset;
        }
    }
    else /* move down,make room for high prio entry*/
    {
        for (t_idx = 0; t_idx < real_num; t_idx++)
        {
            target_a[t_idx].t_idx  = (free_num + t_idx) + start_offset;
        }
    }

    /* save old idx to array */
    o_idx = 0;
    for (idx = old_start_offset; idx < old_start_offset + old_full_num; idx = idx + step)  /* through all entry */
    {
        if (pb->entries[idx])
        {
            if (o_idx >= real_num )
            {
                SYS_FPA_DBG_DUMP("  unexpect real_num %d! \n", real_num);
            }
            target_a[o_idx].o_idx = idx;
            o_idx++;
        }
    }

    {
        int32          tcam_idx_old = 0; /* Original entry tcam index.    */
        int32          tcam_idx_new = 0; /* Next tcam index for the entry.*/
        int32          new_pe_idx = 0; /* Next tcam index for the entry.*/
        ctc_fpa_entry_t* pe = NULL;
        ctc_fpa_block_t* pb_tmp = NULL;

        for (idx = 0; idx < real_num; idx++)
        {

            pe = pb->entries[target_a[idx].o_idx];
            if (pe == NULL)
            {
                SYS_FPA_DBG_INFO("  unexpect pe idx %d! \n", target_a[idx].o_idx);
                continue;
            }

            fpa->get_info_by_pe(fpa->lchip, pe, &pb_tmp);
            tcam_idx_old = fpa_get_index_by_pe_idx(pb_tmp->entry_count, pb_tmp->sub_entry_count[1], pe->offset_a);
            tcam_idx_new = tcam_idx_old + target_a[idx].t_idx - target_a[idx].o_idx;
            new_pe_idx = fpa_get_index_by_fpa_idx_adjust(pb_tmp, p_info, tcam_idx_new);


            if (new_pe_idx > pe->offset_a)
            {
                if (dir0[i] == 0)
                {
                    dir0[i] = 1;
                }

                if (dir0[i] == -1)
                {
#ifndef CTC_SHELL_DEBUG_ON
                    dir1[i] = 1;
#endif
                    pos_a[i] = idx;
                    i++;
                }
            }
            else if(new_pe_idx < pe->offset_a)
            {
                if (dir0[i] == 0)
                {
                    dir0[i] = -1;
                }

                if (dir0[i] == 1)
                {
#ifndef CTC_SHELL_DEBUG_ON
                    dir1[i] = -1;
#endif
                    pos_a[i] = idx;
                    i++;
                }
            }


       SYS_FPA_DBG_INFO("i= %d, entry_id:%d, t_o:%d, t_n:%d, o_idx:%d, n_idx:%d, dir0=%d, dir1:%d, pos:%d\n",
           i, pe->entry_id,target_a[idx].o_idx, target_a[idx].t_idx, pe->offset_a, new_pe_idx,dir0[i], dir1[i], pos_a[i]);

        }
    }

    for (j = 0; j <= i; j++)
    {
        SYS_FPA_DBG_INFO("No.%d  dir0:%d, dir1:%d, pos:%d\n", j, dir0[j], dir1[j], pos_a[j]);
    }

    j= 0;
    left_num = real_num;
    SYS_FPA_DBG_INFO("left_num %d, real_num %d\n", left_num, real_num);

    while (left_num)
    {

        pos = pos_a[j] == -1?left_num:((j>0)?pos_a[j] - pos_a[j-1]:pos_a[j]);

        SYS_FPA_DBG_INFO("dir0:%d, dir1:%d, pos:%d\n", dir0[j], dir1[j], pos);

        SYS_FPA_DBG_INFO("pos:%d, left_num:%d\n", pos, left_num);

        for (idx = 0; idx < pos; idx++)
        {
            if (dir0[j] == 1)
            {
                revise = (pos - 1 - idx);
            }
            else if(dir0[j] == -1)
            {
                revise = idx;
            }
            else
            {
                revise = idx;
            }

            SYS_FPA_DBG_INFO(" move revise:%d, pe:%d from %d to %d!\n",
                             revise,
                             pb->entries[target_a[revise].o_idx]->entry_id,
                             target_a[revise].o_idx, target_a[revise].t_idx);
            /* move revise to temp */
            CTC_ERROR_GOTO(_fpa_usw_entry_move2(fpa,p_tmp_entries[target_a[revise].o_idx],
                                               (target_a[revise].t_idx - target_a[revise].o_idx), p_info), ret, cleanup);

        }

        if (pos < left_num)
        {
            sal_memmove(&target_a[0], &target_a[pos], (left_num - pos) * sizeof(_fpa_target_t));
        }
        left_num = left_num - pos;
        j++;

    }


    /*adjust virtual */
    for (idx = 0 ; idx < full_num; idx++)
    {
        pb_part_new = fpa_get_local_info_by_fpa_idx_adjust(pb_real, p_info, idx, &local_idx_new);
        pb->entries[idx] = pb_part_new->entries[local_idx_new];
    }
    if(old_full_num > full_num)
    {
        sal_memset((pb->entries+full_num), 0, (old_full_num-full_num)*sizeof(ctc_fpa_entry_t*));
    }

    mem_free(p_tmp_entries);
    mem_free(target_a);

    return CTC_E_NONE;

 cleanup:
    mem_free(p_tmp_entries);
    mem_free(target_a);
    return ret;
}


STATIC int32
_fpa_usw_reorder2(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, uint8 type, ctc_fpa_block_info_t* p_info)
{
    int32         idx;
    int32         revise;
    int32         t_idx;
    int32         o_idx;
    _fpa_target_t * target_a = NULL;
    int32         ret        = 0;
    uint8         move_ok;

    uint8         step   = 1;
/*    static double time;*/
/*    clock_t begin,end;*/
    uint32 start_offset = 0;
    uint32 old_start_offset = 0;
    uint32 full_num;
    uint32 old_full_num;
    uint32 free_num;
    uint32 real_num;             /* actual entry number */
    uint32 left_num;
    uint8 is_vblock = 0;
    //uint16 o_idx_adj = 0;
    ctc_fpa_block_t* pb_real = NULL;

/*    begin = clock();*/

    if (p_info->key_size == CTC_FPA_KEY_SIZE_160 && pb->vblock)
    {
        pb_real = pb;
        pb = pb->vblock;
        is_vblock = 1;
    }

    if (is_vblock && pb_real->sub_entry_count[0])
    {
        return _fpa_usw_reorder_virtual(fpa, pb_real, type, p_info);
    }

    SYS_FPA_DBG_FUNC();
    SYS_FPA_DBG_PARAM("  [FPA] p_info->key_size:%u, type:%u, p_info->start_move_num:%d, p_info->sub_count_vary:%d\n", p_info->key_size, type, p_info->start_move_num, p_info->sub_count_vary);

    /* malloc a new array based on new exist entry*/
    old_start_offset = pb->start_offset[p_info->key_size];
    start_offset = pb->start_offset[p_info->key_size] + p_info->start_move_num;

    old_full_num = pb->sub_entry_count[p_info->key_size];
    full_num = pb->sub_entry_count[p_info->key_size] + p_info->sub_count_vary;
    free_num = pb->sub_free_count[p_info->key_size] + p_info->sub_count_vary;
    real_num = full_num - free_num; /* used entry count */

    if(0 == old_full_num || real_num == 0)
    {
        return CTC_E_NONE;
    }

    MALLOC_ZERO(MEM_FPA_MODULE, target_a, real_num * sizeof(_fpa_target_t))
    if(!target_a)
    {
       return CTC_E_NO_MEMORY;
    }

    SYS_FPA_DBG_INFO("  [FPA] reorder real_num:%u, full_num:%u, start_offset:%u\n", real_num, full_num, start_offset);
    /* save target idx to array */
    if (REORDE_TYPE_SCATTER == type)
    {
        for (t_idx = 0; t_idx < real_num; t_idx++)
        {
            target_a[t_idx].t_idx  = (full_num * t_idx / real_num) + start_offset;
        }
    }
    else if (REORDE_TYPE_DECREASE == type) /* move up,make room for low prio entry*/
    {
        for (t_idx = 0; t_idx < real_num; t_idx++)
        {
            target_a[t_idx].t_idx  = t_idx + start_offset;
        }
    }
    else /* move down,make room for high prio entry*/
    {
        for (t_idx = 0; t_idx < real_num; t_idx++)
        {
            target_a[t_idx].t_idx  = (free_num + t_idx) + start_offset;
        }
    }

    /* save old idx to array */
    o_idx = 0;
    for (idx = old_start_offset; idx < old_start_offset + old_full_num; idx = idx + step)  /* through all entry */
    {
        if (pb->entries[idx])
        {
            if (o_idx >= real_num )
            {
                SYS_FPA_DBG_ERROR("  unexpect real_num %d! \n", real_num);
            }
            //SYS_FPA_DBG_INFO("  [part%u]idx in use %u! \n", pb->part, idx);
            target_a[o_idx].o_idx = idx;
            o_idx++;
        }
    }

    left_num = real_num;

    while (left_num)
    {
        for (idx = 0; idx < left_num; idx++)
        {

            revise  = (REORDE_TYPE_INCREASE == type) ? (left_num - 1 - idx) : idx;

            move_ok = 0;

            if (target_a[revise].o_idx == target_a[revise].t_idx) /* stay */
            {
                SYS_FPA_DBG_INFO("stay !\n");

                if (is_vblock)
                {
                    SYS_FPA_DBG_INFO(" move pe:%d from %d to %d!\n",
                                     pb->entries[target_a[revise].o_idx]->entry_id,
                                     target_a[revise].o_idx, target_a[revise].t_idx);
                    /* move revise to temp */
                    CTC_ERROR_GOTO(_fpa_usw_entry_move2(fpa, pb->entries[target_a[revise].o_idx],
                                                       0, p_info), ret, cleanup);
                }

                move_ok = 1;
            }
            else
            {
                if (target_a[revise].o_idx < target_a[revise].t_idx) /* move down */
                {
                    if ((revise == left_num - 1) || (target_a[revise + 1].o_idx > target_a[revise].t_idx))
                    {
                        move_ok = 1;
                    }
                }
                else /* move up */
                {
                    if ((revise == 0) || (target_a[revise - 1].o_idx > target_a[revise].t_idx))
                    {
                        move_ok = 1;
                    }
                }

                if (move_ok)
                {
                    SYS_FPA_DBG_INFO(" move pe:%d from %d to %d!\n",
                        pb->entries[target_a[revise].o_idx]->entry_id,
                        target_a[revise].o_idx, target_a[revise].t_idx);
                    /* move revise to temp */
                    CTC_ERROR_GOTO(_fpa_usw_entry_move2(fpa, pb->entries[target_a[revise].o_idx],
                                                       (target_a[revise].t_idx - target_a[revise].o_idx), p_info), ret, cleanup);
                }
            }

            if (move_ok)
            {
                if (REORDE_TYPE_INCREASE != type)
                {
                    sal_memmove(&target_a[revise], &target_a[revise + 1], (left_num - revise - 1) * sizeof(_fpa_target_t));
                }
                left_num--;
                idx--;
            }

        }
    }

    mem_free(target_a);

/*    end = clock();*/
/*    time = time + ((double)(end - begin) / CLOCKS_PER_SEC);*/
/*    SYS_FPA_DBG_INFO(" t:%lf", time);*/
    pb->cur_trend[p_info->key_size] = type;
    return CTC_E_NONE;

 cleanup:
    mem_free(target_a);
    return ret;
}


/* output:
 * targ, if invalid: 1. all null. 2. prio is the smallest.
 * prev(first null before target), if invalid: 1. before targ no null.
 * next(first null after target), if invalid: 1. targ is invalid 2. targ found, but after targ no null.
 */


/*
 first_valid != first_normal. <==> highest entry exist.
 last_valid  != last_normal. <==> lowest entry exist.
 targ != targ_normal.   <==> targ_normal = -1, targ found but entry is not normal and has highest prio.
 prev === prev_n. next === next_n.
*/
STATIC int32
_fpa_usw_get_indexes2(uint32 prio, ctc_fpa_entry_t* pe, ctc_fpa_block_t* pb, uint8 key_size,
                 int32* targ, int32* prev, int32* next,
                 int32* first_null  , int32* last_null,
                 int32* first_valid, int32* last_valid)
{
    uint8 step = 1;
    int32 idx;

    for (idx = pb->start_offset[key_size]; idx < pb->start_offset[key_size] + pb->sub_entry_count[key_size]; idx = idx + step)
    {
        /* Skip the pe itself */
        if (pe && (pe == pb->entries[idx]))
        {
            continue;
        }

        if (pb->entries[idx] == NULL)
        {
            if (FPA_INVALID_INDEX == *targ)
            {
                *prev = idx;
            }
            else if (FPA_INVALID_INDEX == *next)
            {
                *next = idx;
            }
            if (FPA_INVALID_INDEX == *first_null)
            {
                *first_null = idx;
            }
            *last_null = idx;
        }
        else /* valid entry */
        {
            *last_valid = idx;

            if ((prio > pb->entries[idx]->priority)
                && (FPA_INVALID_INDEX == *targ)) /* found target */
            {
                *targ = idx;
            }

            if (FPA_INVALID_INDEX == *first_valid)  /* found first_valid */
            {
                *first_valid = idx;
            }
        }
    }
    if (prio > pb->last_priority[key_size])
    {
        pb->decrease_trend[key_size] = 0;
        pb->increase_trend[key_size]++;
    }
    else
    {
        pb->decrease_trend[key_size]++;
        pb->increase_trend[key_size] = 0;
    }

    pb->last_priority[key_size] = prio;

    return CTC_E_NONE;
}

STATIC int32
_fpa_usw_get_offset2(ctc_fpa_t* fpa, ctc_fpa_entry_t* pe, ctc_fpa_block_t* pb, uint8 key_size,
                uint32 prio, int32* target, uint32* move_num_out)
{
    int32  target_out;
    int32  prev        = FPA_INVALID_INDEX;
    int32  next        = FPA_INVALID_INDEX;
    int32  first_valid = FPA_INVALID_INDEX;
    int32  last_valid  = FPA_INVALID_INDEX;
    int32  first_null  = FPA_INVALID_INDEX;
    int32  last_null   = FPA_INVALID_INDEX;
    int32  targ        = FPA_INVALID_INDEX;
    int32  dir = 0;
    uint8  step = 1;
    uint32 move_num = 0;

    /* block is empty. */
   /*  if (pb->entry_count == pb->free_count)*/
   /*  {*/
  /*       *target = pb->entry_count >> 1;*/
   /*      return CTC_E_NONE;*/
   /*  }*/


    _fpa_usw_get_indexes2(prio, pe, pb, key_size, &targ, &prev, &next,
                     &first_null, &last_null, &first_valid, &last_valid);

    if (FPA_INVALID_INDEX == targ)
    {
        if(FPA_INVALID_INDEX == first_valid)
        {
            target_out = pb->start_offset[key_size] + (pb->sub_entry_count[key_size] >> 1);   /*when set entry priority, only one entry exist(itself)*/
        }
        else if (SUB_BLOCK_END == last_valid)    /*last valid entry in the end of block*/
        {
            target_out = SUB_BLOCK_END;
            CTC_ERROR_RETURN(_fpa_usw_entry_shift_up2(fpa, pb, target_out, prev, step, &move_num));
        }
        else
        {
            target_out = NEXT_IDX(last_valid, step); /* must be null */
        }
    }
    else if(first_valid == targ)
    {
        if(SUB_BLOCK_START == targ)   /*in the start of the block*/
        {
            target_out = SUB_BLOCK_START;
            CTC_ERROR_RETURN(_fpa_usw_entry_shift_down2(fpa, pb, target_out, next, step, &move_num));
        }
        else
        {
            target_out = PREV_IDX(targ, step);
        }
    }
    else
    {
        _fpa_usw_get_shift_direction(prev, targ, next, &dir);
        if (dir == 1)
        {
            target_out = targ;
            /*
             * Move the entry at the targ index to target_index+1. This may
             * mean shifting more entries down to make room. In other words,
             * shift the targ index and any that follow it down 1 as far as the
             * next empty index.
             */
            SYS_FPA_DBG_INFO("  %%INFO: from %d to %d do shift down \n", target_out, next - step);
            CTC_ERROR_RETURN(_fpa_usw_entry_shift_down2(fpa, pb, target_out, next, step, &move_num));
        }
        else
        {
            /*
             * for Shifting UP , the targ is one up.
             */
            target_out = targ - step;

            SYS_FPA_DBG_INFO("  %%INFO: from %d to %d do shift up \n", target_out, prev + step);
            CTC_ERROR_RETURN(_fpa_usw_entry_shift_up2(fpa, pb, target_out, prev, step, &move_num));
        }
    }


    *target = target_out;
    *move_num_out = move_num;
    return CTC_E_NONE;
}

STATIC int32
_fpa_usw_adjust_resource2(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, uint8 key_size)
{
    int8   idx1 = 0;
    int8   idx2 = 0;
    uint8  step = 1;
    uint8  factor = 0;
    uint8  adjust_ok = 0;
    uint8  require_step = 0;
    uint16 up_free_count = 0;
    uint16 down_free_count = 0;
    uint16 update_entry_count = 0;
    uint8 part = 0;
    ctc_fpa_block_t* pb_part = NULL;
    ctc_fpa_block_info_t block_info;

    for(idx1 = 0; idx1 < CTC_FPA_KEY_SIZE_NUM; idx1++)
    {
        if(idx1 < key_size)
        {
            if (idx1 == CTC_FPA_KEY_SIZE_160 && pb->vblock)
            {
                up_free_count += pb->vblock->sub_free_count[idx1]/key_size;
            }
            else
            {
                up_free_count += FPA_FREE_COUNT(idx1);
            }
        }
        else
        {
            down_free_count += FPA_FREE_COUNT(idx1);
        }
    }
    require_step = 1;

    if (pb->vblock)
    {
        if (key_size == CTC_FPA_KEY_SIZE_320 && pb->start_offset[CTC_FPA_KEY_SIZE_320] == 0)
        {
            up_free_count = 0; /*aways use down*/
        }
    }

    /*one condition not care: up_free_count < step and down_free_count < step, but up+down >= step*/
    if((up_free_count >= down_free_count) && (up_free_count >= require_step))
    {
         /*key size must greater than CTC_FPA_KEY_SIZE_160*/
        for(idx1 = key_size - 1; idx1 >= 0; idx1--)
        {
            if (pb->vblock)
            {
                uint32 free_cnt = 0;
                uint32 entry_cnt = 0;
                uint32 adjust_cnt = 0;

                if (key_size == CTC_FPA_KEY_SIZE_320)
                {
                    require_step = 2;
                }
                else if(key_size == CTC_FPA_KEY_SIZE_640)
                {
                    require_step = (idx1 == CTC_FPA_KEY_SIZE_160)?3:1;
                }

                if (idx1 == CTC_FPA_KEY_SIZE_160)
                {
                    free_cnt =  pb->vblock->sub_free_count[idx1];
                    entry_cnt =  pb->vblock->sub_entry_count[idx1];

                    if (free_cnt < require_step)
                    {
                        continue;
                    }

                    if (pb->start_offset[CTC_FPA_KEY_SIZE_320] == 0)
                    {
                        continue;
                    }

                    if (free_cnt > (entry_cnt / 16))
                    {
                        factor = 2;     /*take half of free*/
                    }
                    else
                    {
                        factor = 1;     /*take all*/
                    }

                    update_entry_count = free_cnt / require_step;
                    update_entry_count = update_entry_count / factor * require_step;
                    update_entry_count = update_entry_count ? update_entry_count : require_step;

                    /* reorder the virtual block*/
                    adjust_cnt = update_entry_count / require_step;

                    if (pb->start_offset[CTC_FPA_KEY_SIZE_320] < adjust_cnt)
                    {
                        adjust_cnt = pb->start_offset[CTC_FPA_KEY_SIZE_320];
                        update_entry_count = adjust_cnt*require_step;
                    }

                    if (pb->sub_entry_count[CTC_FPA_KEY_SIZE_160])
                    {
                        pb->sub_entry_count[0] = adjust_cnt;
                    }
                    CTC_FPA_BUILD_BLOCK_INFO(block_info, idx1, 0, -update_entry_count, 0);
                    _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_DECREASE, &block_info);
                    pb->sub_entry_count[0] = 0;


                    pb_part = pb;
                    for (part = 0; part < key_size && pb_part; part++)
                    {
                        pb_part->sub_entry_count[idx1] -= adjust_cnt;
                        pb_part->sub_free_count[idx1] -= adjust_cnt;
                        pb_part = pb_part->next;
                    }

                    pb->vblock->sub_entry_count[idx1] -= update_entry_count;
                    pb->vblock->sub_free_count[idx1] -= update_entry_count;

                    //pb->vblock->entry_count -= (update_entry_count / step);
                    //pb->vblock->free_count -= (update_entry_count / step);


                    /*reorder the 320 offset*/
                    for (idx2 = idx1 + 1; idx2 < key_size; idx2++)
                    {
                        CTC_FPA_BUILD_BLOCK_INFO(block_info, idx2, -adjust_cnt, 0, 0);
                        _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_DECREASE, &block_info);    /*move up*/
                        pb->start_offset[idx2] -= adjust_cnt;
                        pb->next->start_offset[idx2] -= adjust_cnt;
                    }

                }
                else
                {
                    uint32 free_cnt320 = 0;
                    uint32 free_cnt160 = 0;
                    uint32 free_cnt = 0;

                    free_cnt160 =  pb->vblock->sub_free_count[CTC_FPA_KEY_SIZE_160];
                    free_cnt320 = FPA_FREE_COUNT(CTC_FPA_KEY_SIZE_320);
                    free_cnt = (free_cnt160 > free_cnt320)?free_cnt320:free_cnt160;


                    if (free_cnt == 0)
                    {
                        if (pb->part_num == 3 && free_cnt320 >= 2 && free_cnt160 == 0)
                        {
                            int16 i = 0;
                            int32 single_cnt = 0;
                            int32 old_cnt = 0;

                            free_cnt = free_cnt320;

                            if (free_cnt >= 4)
                            {
                                update_entry_count = free_cnt / 4;
                            }
                            else
                            {
                                update_entry_count = free_cnt / 2;                            }
                            CTC_FPA_BUILD_BLOCK_INFO(block_info, CTC_FPA_KEY_SIZE_320, (update_entry_count), -(update_entry_count), 0)
                            _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_INCREASE, &block_info);    /*move down*/


                            pb->sub_entry_count[CTC_FPA_KEY_SIZE_320] -= (update_entry_count);
                            pb->sub_free_count[CTC_FPA_KEY_SIZE_320] -= (update_entry_count);
                            pb->start_offset[CTC_FPA_KEY_SIZE_320] += update_entry_count;
                            if (pb->next)
                            {
                                pb->next->sub_entry_count[CTC_FPA_KEY_SIZE_320] -= (update_entry_count);
                                pb->next->sub_free_count[CTC_FPA_KEY_SIZE_320] -= (update_entry_count);
                                pb->next->start_offset[CTC_FPA_KEY_SIZE_320] += update_entry_count;
                            }


                            single_cnt = update_entry_count;
                            old_cnt = pb->sub_entry_count[CTC_FPA_KEY_SIZE_160] ;

                            pb_part = pb;
                            for (part = 0; part < 2 && pb_part; part++)
                            {
                                pb_part->sub_entry_count[CTC_FPA_KEY_SIZE_160] += single_cnt;
                                pb_part->sub_free_count[CTC_FPA_KEY_SIZE_160] += single_cnt;
                                pb_part = pb_part->next;
                            }

                            for (i = pb->vblock->sub_entry_count[CTC_FPA_KEY_SIZE_160] - 1; i >= old_cnt*2 && i >= 0; i--)
                            {
                                pb->vblock->entries[i + single_cnt*2] = pb->vblock->entries[i];
                                pb->vblock->entries[i] = NULL;
                                SYS_FPA_DBG_INFO("Move Vblock db form %d -> %d\n", i, i + single_cnt*2);
                            }

                            if (old_cnt > 0)
                            {
                                for (i = old_cnt*2 - 1; i >= old_cnt && i >= 0; i--)
                                {
                                    pb->vblock->entries[i + single_cnt] = pb->vblock->entries[i];
                                    pb->vblock->entries[i] = NULL;
                                    SYS_FPA_DBG_INFO("Move Vblock db form %d -> %d\n", i, i + single_cnt);
                                }
                            }

                            //pb->vblock->entry_count += single_cnt*2;
                            //pb->vblock->free_count += single_cnt*2;
                            pb->vblock->sub_entry_count[CTC_FPA_KEY_SIZE_160] += single_cnt*2;
                            pb->vblock->sub_free_count[CTC_FPA_KEY_SIZE_160] += single_cnt*2;

                            adjust_cnt = update_entry_count;

                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        update_entry_count = free_cnt;
                        adjust_cnt = update_entry_count;
                    }

                    /*reorder the 160 block*/
                    CTC_FPA_BUILD_BLOCK_INFO(block_info, CTC_FPA_KEY_SIZE_160, 0, -update_entry_count, 0);
                   _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_DECREASE, &block_info);

                    pb->vblock->sub_entry_count[CTC_FPA_KEY_SIZE_160] -= update_entry_count;
                    pb->vblock->sub_free_count[CTC_FPA_KEY_SIZE_160] -= update_entry_count;
                    //pb->vblock->entry_count -= (update_entry_count / step);
                    //pb->vblock->free_count -= (update_entry_count / step);

                    if (pb->next && pb->next->next)
                    {
                        pb_part = pb->next->next;
                        pb_part->sub_entry_count[CTC_FPA_KEY_SIZE_160] -= update_entry_count;
                        pb_part->sub_free_count[CTC_FPA_KEY_SIZE_160] -= update_entry_count;
                    }

                    /*reorder the 320 block*/
                    CTC_FPA_BUILD_BLOCK_INFO(block_info, idx1, 0, -update_entry_count, 0);
                    _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_SCATTER, &block_info);

                    pb->sub_entry_count[idx1] -= update_entry_count;
                    pb->sub_free_count[idx1] -= update_entry_count;

                    if (pb->next)
                    {
                        pb->next->sub_entry_count[idx1] -= update_entry_count;
                        pb->next->sub_free_count[idx1] -= update_entry_count;
                    }
                }

                /*adjust the key size count*/
                pb_part = pb;
                for (part = 0; part < key_size && pb_part; part++)
                {
                    pb_part->sub_entry_count[key_size] += adjust_cnt;
                    pb_part->sub_free_count[key_size] += adjust_cnt;
                    pb_part->start_offset[key_size] -= adjust_cnt;   /*no need reorder*/
                    if (key_size==CTC_FPA_KEY_SIZE_640 && part==2)
                    {
                        pb_part->start_offset[key_size-1] = pb_part->start_offset[key_size];
                    }
                    pb_part = pb_part->next;
                }

                adjust_ok = 1;

                break;

            }
            else
            {
                if (FPA_FREE_COUNT(idx1) >= require_step)
                {
                    adjust_ok = 1;
                    if (FPA_FREE_COUNT(idx1) > (pb->entry_count / 16))
                    {
                        factor = 2;     /*take half of free*/
                    }
                    else
                    {
                        factor = 1;     /*take all*/
                    }
                    update_entry_count = FPA_FREE_COUNT(idx1) / require_step;
                    update_entry_count = update_entry_count / factor * require_step;
                    update_entry_count = update_entry_count ? update_entry_count : require_step;
                    CTC_FPA_BUILD_BLOCK_INFO(block_info, idx1, 0, -update_entry_count, 0);
                    _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_SCATTER, &block_info);
                    pb->sub_entry_count[idx1] -= update_entry_count;
                    pb->sub_free_count[idx1] -= update_entry_count;
                    for (idx2 = idx1 + 1; idx2 < key_size; idx2++)
                    {
                        CTC_FPA_BUILD_BLOCK_INFO(block_info, idx2, -update_entry_count, 0, 0);
                        _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_DECREASE, &block_info);    /*move up*/
                        pb->start_offset[idx2] -= update_entry_count;
                    }
                    pb->sub_entry_count[key_size] += (update_entry_count / require_step);
                    pb->sub_free_count[key_size] += (update_entry_count / require_step);
                    pb->start_offset[key_size] -= update_entry_count;   /*no need reorder*/
                    break;
                }
            }
        }
    }
    else if(down_free_count >= require_step)
    {
         /*key size must less than CTC_FPA_KEY_SIZE_640*/
        for(idx1 = key_size + 1; idx1 < CTC_FPA_KEY_SIZE_NUM; idx1++)
        {
            if(FPA_FREE_COUNT(idx1) > 0)
            {
                adjust_ok = 1;
                if(FPA_FREE_COUNT(idx1) > (pb->entry_count/16))
                {
                    factor = 2;
                }
                else
                {
                    factor = 1;
                }
                update_entry_count = FPA_FREE_COUNT(idx1) / factor;
                update_entry_count = update_entry_count ? update_entry_count : step;
                CTC_FPA_BUILD_BLOCK_INFO(block_info, idx1, update_entry_count, -update_entry_count, 0);
                _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_SCATTER, &block_info);

                pb->sub_entry_count[idx1] -= update_entry_count;
                pb->sub_free_count[idx1] -= update_entry_count;
                pb->start_offset[idx1] += update_entry_count;

                for(idx2 = idx1 - 1; idx2 > key_size; idx2--)
                {
                    CTC_FPA_BUILD_BLOCK_INFO(block_info, idx2, update_entry_count, 0, 0);
                    _fpa_usw_reorder2(fpa, pb, REORDE_TYPE_INCREASE, &block_info);    /*move down*/
                    pb->start_offset[idx2] += update_entry_count;
                }
                pb->sub_entry_count[key_size] += (update_entry_count / require_step);
                pb->sub_free_count[key_size] += (update_entry_count / require_step);


                /* ==========================================================================*/
                /*process link block*/
                if (pb->part_num > 1)
                {
                    uint8 adjust_part = 0;
                    pb_part = pb;
                    for (part = 1; part < idx1 && pb_part->next; part++)
                    {
                        pb_part = pb_part->next;
                        pb_part->sub_entry_count[idx1] -= update_entry_count;
                        pb_part->sub_free_count[idx1] -= update_entry_count;
                        pb_part->start_offset[idx1] += update_entry_count;
                    }

                    for (idx2 = idx1 - 1; idx2 > key_size; idx2--)
                    {
                        pb_part = pb;
                        for (part = 1; part < idx2 && pb_part->next; part++)
                        {
                            pb_part = pb_part->next;
                            pb_part->start_offset[idx2] += update_entry_count;
                        }
                    }

                    /*increase the block entry count*/
                    pb_part = pb;
                    adjust_part = (key_size == CTC_FPA_KEY_SIZE_160)? idx1:key_size;

                    for (part = 1; part < adjust_part && pb_part->next; part++)
                    {
                        pb_part = pb_part->next;
                        pb_part->sub_entry_count[key_size] += (update_entry_count / require_step);
                        pb_part->sub_free_count[key_size] += (update_entry_count / require_step);
                    }

                    /*for 3 part, adjust the third 160 block*/
                    if (idx1 == CTC_FPA_KEY_SIZE_640 && adjust_part != 3 && pb->part_num == 3)
                    {
                        pb_part = pb->next->next;
                        pb_part->sub_entry_count[CTC_FPA_KEY_SIZE_160] += (update_entry_count / require_step);
                        pb_part->sub_free_count[CTC_FPA_KEY_SIZE_160] += (update_entry_count / require_step);
                    }

                    if (pb->vblock)
                    {
                        uint32 adjust_cnt = 0;
                        uint32 single_cnt = 0;
                        uint32 old_cnt = 0;
                        int32 i = 0;
                        uint8 adjust_idx = CTC_FPA_KEY_SIZE_160;

                        single_cnt = update_entry_count / require_step;
                        old_cnt =  (pb->sub_entry_count[adjust_idx] >= single_cnt)?
                            pb->sub_entry_count[adjust_idx] - single_cnt:0;
                        adjust_cnt = (key_size == CTC_FPA_KEY_SIZE_320)?single_cnt:
                        (single_cnt*(idx1 > CTC_FPA_KEY_SIZE_320 ?pb->part_num:idx1));

                        if (key_size == adjust_idx && pb->vblock->sub_entry_count[CTC_FPA_KEY_SIZE_160])
                        {
                            if (pb->part_num == 3)
                            {
                                for (i = old_cnt*3 + pb->sub_entry_count[CTC_FPA_KEY_SIZE_320] + single_cnt - 1;
                                    i >= old_cnt*2 && i >= 0; i--)
                                {
                                    pb->vblock->entries[i + single_cnt*2] = pb->vblock->entries[i];
                                    pb->vblock->entries[i] = NULL;
                                    SYS_FPA_DBG_INFO("Move Vblock db form %d -> %d\n", i, i + single_cnt*2);
                                }
                            }

                            if (old_cnt > 0)
                            {
                                for (i = old_cnt*2 - 1; i >= old_cnt && i >= 0; i--)
                                {
                                    pb->vblock->entries[i + single_cnt] = pb->vblock->entries[i];
                                    pb->vblock->entries[i] = NULL;
                                    SYS_FPA_DBG_INFO("Move Vblock db form %d -> %d\n", i, i + single_cnt);
                                }
                            }
                        }

                        if (key_size == adjust_idx || (idx1 == CTC_FPA_KEY_SIZE_640 && pb->part_num == 3))
                        {
                            //pb->vblock->entry_count += adjust_cnt;
                            //pb->vblock->free_count += adjust_cnt;
                            pb->vblock->sub_entry_count[adjust_idx] += adjust_cnt;
                            pb->vblock->sub_free_count[adjust_idx] += adjust_cnt;
#if 0
                            if (key_size == adjust_idx && pb->part_num == 3 &&
                                pb->vblock->free_count - adjust_cnt == 0)
                            {
                                for (i = pb->vblock->entry_count - adjust_cnt - 1; i >= 0; i--)
                                {
                                    pb->vblock->entries[i + adjust_cnt] = pb->vblock->entries[i];
                                    pb->vblock->entries[i] = NULL;
                                    SYS_FPA_DBG_INFO("Move Vblock db form %d -> %d\n", i, i + adjust_cnt);
                                }
                            }
#endif
                        }


                    }

                }

                break;
            }
        }
    }
    if(!adjust_ok)
    {
        return CTC_E_NO_RESOURCE;
    }
    else
    {
        pb->cur_trend[key_size] = 0;
    }

    return CTC_E_NONE;
}


/*
 * set priority of entry specific by pe and pb. pe must be in pb
 */
int32
fpa_usw_set_entry_prio2(ctc_fpa_t* fpa, ctc_fpa_entry_t* pe, ctc_fpa_block_t* pb, uint8 key_size, uint32 prio)
{
    int32  target = 0;
    int32  temp;
    int32  temp1;
    uint32 move_num = 0;
    uint32 old_prio = 0;
    ctc_fpa_block_t* pb_real = NULL;
    ctc_fpa_block_info_t block_info;

    /* If the priority isn't changing, just return.*/
    old_prio = pe->priority;
    if (old_prio == prio)
    {
        return(CTC_E_NONE);
    }

    /*for 160/320/480 mixed alloc 160*/
    pb_real = pb;
    if (key_size == CTC_FPA_KEY_SIZE_160 && pb->vblock)
    {
        pb = pb->vblock;
    }

    if (0 == pb->sub_free_count[key_size])   /*need adjust resource*/
    {
        CTC_ERROR_RETURN(_fpa_usw_adjust_resource2(fpa, pb_real, key_size));
    }

    if ((0 == pb->free_count) || (0 == pb->sub_free_count[key_size]))
    {
        return CTC_E_NO_RESOURCE;
    }

    CTC_ERROR_RETURN(_fpa_usw_get_offset2(fpa, pe, pb, key_size, prio, &target, &move_num));
    temp  = target;
    temp1 = pe->offset_a;

    if (key_size == CTC_FPA_KEY_SIZE_160 && pb_real->vblock)
    {
        temp1 = fpa_get_index_by_pe_idx(pb_real->entry_count, pb_real->sub_entry_count[key_size], temp1);
    }

    if ((temp - temp1) != 0)
    {
        CTC_ERROR_RETURN(_fpa_usw_entry_move2(fpa, pe, (temp - temp1), NULL));
    }

    /* Assign the requested priority to the entry. */
    pe->priority = prio;

    /* do reorde after update count. this process is independant. */
    if (DO_REORDER(move_num, pb->sub_entry_count[key_size]))
    {
        CTC_FPA_BUILD_BLOCK_INFO(block_info, key_size, 0, 0, 0);
        CTC_ERROR_RETURN(_fpa_usw_reorder2(fpa, pb, REORDE_TYPE_SCATTER, &block_info));
    }

    return(CTC_E_NONE);
}

/*
 * worst is best
 */
int32
fpa_usw_alloc_offset2(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, uint8 key_size, uint32 prio, uint32* block_index)
{
    int32 target = 0;
    uint8 step = 1;
    uint8 part = 0;
    ctc_fpa_block_t* pb_part = NULL;
    ctc_fpa_block_t* pb_real = NULL;
    ctc_fpa_block_info_t block_info;

    CTC_PTR_VALID_CHECK(pb);
    CTC_PTR_VALID_CHECK(block_index);

    if (pb->free_count < step )
    {
        if (pb->vblock)
        {
            if (pb->vblock->free_count < key_size )
            {
                return CTC_E_NO_RESOURCE;
            }
        }
        else
        {
            return CTC_E_NO_RESOURCE;
        }
    }

    /*for 160/320/480 mixed alloc 160*/
    pb_real = pb;
    if (key_size == CTC_FPA_KEY_SIZE_160 && pb->vblock)
    {
        pb = pb->vblock;
    }


    if (0 == pb->sub_free_count[key_size])   /*need adjust resource*/
    {
        CTC_ERROR_RETURN(_fpa_usw_adjust_resource2(fpa, pb_real, key_size));
    }

    CTC_FPA_BUILD_BLOCK_INFO(block_info, key_size, 0, 0, 0);
    if (pb->cur_trend[key_size] != REORDE_TYPE_SCATTER && pb->cur_trend[key_size] != REORDE_TYPE_DECREASE && DO_PRESS(pb->decrease_trend[key_size]))
    {
        CTC_ERROR_RETURN(_fpa_usw_reorder2(fpa, pb, REORDE_TYPE_DECREASE, &block_info));
    }
    else if (pb->cur_trend[key_size] != REORDE_TYPE_SCATTER && pb->cur_trend[key_size] != REORDE_TYPE_INCREASE && DO_PRESS(pb->increase_trend[key_size]))
    {
        CTC_ERROR_RETURN(_fpa_usw_reorder2(fpa, pb, REORDE_TYPE_INCREASE, &block_info));
    }
    else if (DO_REORDER(pb->move_num[key_size], pb->sub_entry_count[key_size]) && pb->cur_trend[key_size] != REORDE_TYPE_SCATTER)
    {
        CTC_ERROR_RETURN(_fpa_usw_reorder2(fpa, pb, REORDE_TYPE_SCATTER, &block_info));
    }

    CTC_ERROR_RETURN(_fpa_usw_get_offset2(fpa, NULL, pb, key_size, prio, &target, &pb->move_num[key_size]));

    *block_index = target;

    (pb->free_count) -= step;
    (pb->sub_free_count[key_size])--;

    /*Adjust for Mixed 160/320/480*/
    if (key_size == CTC_FPA_KEY_SIZE_160 && pb_real->vblock)
    {
        pb = pb_real;

        if (target >= pb->sub_entry_count[key_size]*2)
        {
            pb_part = pb->next->next;
        }
        else if (target >= pb->sub_entry_count[key_size])
        {
            pb_part = pb->next;
        }
        else
        {
            pb_part = pb;
        }

        (pb_part->free_count) -= step;
        (pb_part->sub_free_count[key_size])--;
    }

    /*process link block*/
    pb_part = pb;
    for (part = 1; part < key_size && pb_part->next; part++)
    {
        pb_part = pb_part->next;
        (pb_part->free_count) -= step;
        (pb_part->sub_free_count[key_size])--;
    }

    return CTC_E_NONE;
}


/*
 * worst is best
 */
int32
fpa_usw_free_offset2(ctc_fpa_block_t* pb, uint32 block_index)
{
    uint8 step = 1;
    uint8 part = 0;
    ctc_fpa_block_t* pb_part = NULL;
    int8 key_size = 0;  /*must use int8, or it will always be true in for loop*/

    /*Adjust for Mixed 160/320/480*/
    if (pb->vblock
        && ((block_index >= pb->entry_count)
    || block_index < pb->sub_entry_count[CTC_FPA_KEY_SIZE_160]))
    {
        ctc_fpa_block_t* pb_v = NULL;
        uint32 fpa_index = 0;

        fpa_index = fpa_get_index_by_pe_idx(pb->entry_count, pb->sub_entry_count[CTC_FPA_KEY_SIZE_160], block_index);

        pb_v = pb->vblock;
        pb_v->free_count += step;
        key_size = CTC_FPA_KEY_SIZE_160;

        (pb_v->sub_free_count[key_size])++;
        pb_v->entries[fpa_index] = NULL;
        pb_v->decrease_trend[key_size]  = 0;
        pb_v->increase_trend[key_size]  = 0;
        pb_v->cur_trend[key_size]    = 0;

        pb = fpa_get_local_info_by_fpa_idx(pb, fpa_index, (int32*)&block_index);

    }


    for(key_size = CTC_FPA_KEY_SIZE_640; key_size >= CTC_FPA_KEY_SIZE_80; key_size--)
    {
        if((block_index >= pb->start_offset[key_size]) && (pb->sub_entry_count[key_size] > 0))
        {
            pb->free_count += step;
            (pb->sub_free_count[key_size])++;
            pb->entries[block_index] = NULL;

            pb->decrease_trend[key_size]  = 0;
            pb->increase_trend[key_size]  = 0;
            pb->cur_trend[key_size]    = 0;


            /*process link block*/
            pb_part = pb;
            for (part = 1; part < key_size && pb_part->next; part++)
            {
                pb_part = pb_part->next;

                pb_part->free_count += step;
                (pb_part->sub_free_count[key_size])++;
                pb_part->entries[block_index] = NULL;

                pb_part->decrease_trend[key_size]  = 0;
                pb_part->increase_trend[key_size]  = 0;
                pb_part->cur_trend[key_size]    = 0;
            }

            break;
        }
    }



    return CTC_E_NONE;
}

int32
fpa_usw_scatter2(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info)
{
    CTC_ERROR_RETURN(_fpa_usw_reorder2(fpa, pb, REORDE_TYPE_SCATTER, p_info));

    pb->move_num[p_info->key_size] = 0;
    return CTC_E_NONE;
}

int32
fpa_usw_increase2(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info)
{
    CTC_ERROR_RETURN(_fpa_usw_reorder2(fpa, pb, REORDE_TYPE_INCREASE, p_info));

    pb->move_num[p_info->key_size] = 0;
    return CTC_E_NONE;
}

int32
fpa_usw_decrease2(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, ctc_fpa_block_info_t* p_info)
{
    CTC_ERROR_RETURN(_fpa_usw_reorder2(fpa, pb, REORDE_TYPE_DECREASE, p_info));

    pb->move_num[p_info->key_size] = 0;
    return CTC_E_NONE;
}

int32
fpa_usw_reorder_virtual(ctc_fpa_t* fpa, ctc_fpa_block_t* pb, uint8 type, ctc_fpa_block_info_t* p_info)
{
    return _fpa_usw_reorder_virtual(fpa, pb, type, p_info);
}



